package com.cn.redis.dao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Repository;
/**
 * string,object
 * @author Han
 */

/**
 * 在这个版本里，每个connection都是新创建的。所以无法直接通过template控制事务。dao层单独出来没有意义
 * @Repository
 * @author Han
 */
public class DefaultRedisDao<K,V> extends RedisTemplate<K,V>{
	@Autowired
	public DefaultRedisDao(RedisConnectionFactory connectionFactory){
		super.setConnectionFactory(connectionFactory);
		setKeySerializer(new StringRedisSerializer());
		setValueSerializer(new JdkSerializationRedisSerializer());
	}
	
	/**
	 * add value
	 * 
	 * @param key
	 * @param value
	 * @param expire
	 * @return
	 */
	public boolean set(final K key, final V value, final long expire) {
		boolean result = execute(new RedisCallback<Boolean>() {
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<K> serializer = (RedisSerializer<K>) getKeySerializer();
				byte[] k = serializer.serialize(key);
				byte[] v = ((RedisSerializer<V>)getValueSerializer()).serialize(value);
				connection.set(k, v);
				connection.expire(k, expire);
				return true;
			}
		},true);
		return result;
	}

	public int mSet(final Map<K, V> data, final long expire) {
		if (data == null) {
			return 0;
		}
		int result = execute(new RedisCallback<Integer>() {
			@Override
			public Integer doInRedis(RedisConnection connection) throws DataAccessException {
				int inc = 0;
				RedisSerializer<K> serializer = (RedisSerializer<K>) getKeySerializer();
				Map<byte[], byte[]> map = new HashMap<byte[], byte[]>();
				for (K k : data.keySet()) {
					V v = data.get(k);
					byte[] kbt = serializer.serialize(k);
					byte[] vbt = ((RedisSerializer<V>)getValueSerializer()).serialize(v);
					if (vbt != null) {
						connection.set(kbt, vbt);
						connection.expire(kbt, expire);
						++inc;
					}
				}
				return inc;
			}
		});
		return result;
	}

	/**
	 * get value
	 * 
	 * @param key
	 * @return
	 */
	public V get(final K key) {
		V v = execute(new RedisCallback<V>() {
			public V doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<K> serializer = (RedisSerializer<K>) getKeySerializer();
				byte[] k = serializer.serialize(key);
				byte[] value = connection.get(k);
				return (V) getValueSerializer().deserialize(value);
			}

		});
		return v;
	}

	/**
	 * key in()
	 * 
	 * @param keys
	 * @return
	 */
	public List<V> mGet(final K[] keys) {
		List<V> values = execute(new RedisCallback<List<V>>() {
			@Override
			public List<V> doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<K> serializer = (RedisSerializer<K>) getKeySerializer();
				List<byte[]> bytes = new ArrayList<byte[]>();
				List<V> result = new ArrayList<V>();
				for (K key : keys) {
					byte[] k = serializer.serialize(key);
					bytes.add(k);
				}
				int size = bytes.size();

				byte[][] keyArray = new byte[size][];

				for (int i = 0; i < keyArray.length; i++) {
					keyArray[i] = bytes.get(i);
				}
				List<byte[]> temp = connection.mGet(keyArray);
				for (byte[] bt : temp) {
					V v = (V) getValueSerializer().deserialize(bt);
					if (v != null) {
						result.add(v);
					}
				}
				return result;

			}
		});
		return values;
	}
}
